package com.le.tester.book.concurrentjavafight.l_13;

import javax.naming.InsufficientResourcesException;
import java.util.concurrent.TimeUnit;

/**
 * createTime：2024/5/11 13:49
 * description：通过tryLock来避免锁顺序死锁
 */
public class Transfer {
    public boolean transferMoney(Account fromAcct, Account toAcct, DollarAmount amount,
                                 long timeOut, TimeUnit timeUnit) throws InsufficientResourcesException, InterruptedException {

        long fixedDelay = this.getFixedDelayComponentNanos(timeOut, timeUnit);
        long randMod = getRandomDelayModulusNanos(timeOut, timeUnit);
        long stopTime = System.nanoTime() + timeUnit.toNanos(timeOut);

        while (true) {
            if (fromAcct.lock.tryLock()) {
                try {
                    if (toAcct.lock.tryLock()) {
                        try {
                            if (fromAcct.getBalance().compareTo(amount) < 0) {
                                throw new InsufficientResourcesException();
                            } else {
                                fromAcct.debit(amount);
                                toAcct.credit(amount);
                                return true;
                            }
                        } finally {
                            toAcct.lock.unLock();
                        }
                    }
                } finally {
                    fromAcct.lock.unLock();
                }

            }

            if (System.nanoTime() < stopTime) {
                return false;
            }
            Thread.sleep(100);
        }
    }

    private long getRandomDelayModulusNanos(long timeOut, TimeUnit timeUnit) {
        return 0;
    }

    private long getFixedDelayComponentNanos(long timeOut, TimeUnit timeUnit) {
        return 0;
    }
}

class Account {
    public Lock lock;
    DollarAmount balance;

    public Account(DollarAmount balance) {
        this.balance = balance;
    }

    public DollarAmount getBalance() {
        return balance;
    }

    public void debit(DollarAmount amount) {
    }

    public void credit(DollarAmount amount) {
    }
}

class DollarAmount {

    public int compareTo(DollarAmount amount) {
        return 0;
    }
}
